/**********************************************************************************
 * Copyright (c) <2013-2015>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **********************************************************************************/

/**********************************************************************************
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which
 * might include those applicable to Huawei LiteOS of U.S. and the country in which you
 * are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance
 * with such applicable export control laws and regulations.
 **********************************************************************************/

#include "lwip/opt.h"
#include "ctype.h"

#if LWIP_ENABLE_LOS_SHELL_CMD
#include "lwip/tcpip.h"
#include "lwip/netif.h"
#include "lwip/netdb.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#ifdef LWIP_PPPOE
#include "netif/ppp.h"
#endif
#include "lwip/ip_addr.h"
#include "lwip/icmp.h"
#include "lwip/sockets.h"
#include "lwip/inet_chksum.h"
#include "los_sys.h"
#include "los_config.h"
#include "string.h"
#include "limits.h"
#include "stdlib.h"
#include "stdio.h"
#include "poll.h"
#include "unistd.h"

#include "lwip/api_shell.h"
#include "lwip/tftpc.h"
#include "lwip/sntp.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "lwip/udp.h"
#include "lwip/tcp_impl.h"
#include "lwip/raw.h"


#ifdef LOSCFG_SHELL
#include "shcmd.h"
#include "shell.h"
#endif

#if LWIP_ARP
extern sys_sem_t ip_conflict_detect;
#endif
extern int tcpip_init_finish;
extern struct etharp_entry arp_table[ARP_TABLE_SIZE];
extern UINT32 GetTimer2Value(void);
extern const char * const tcp_state_str[];
extern int get_unused_socket_num(void);

#define IFCONFIG_OPTION_SET_IP          (1)
#define IFCONFIG_OPTION_SET_NETMASK     (1 << 1)
#define IFCONFIG_OPTION_SET_GW          (1 << 2)
#define IFCONFIG_OPTION_SET_HW          (1 << 3)
#define IFCONFIG_OPTION_SET_UP          (1 << 4)
#define IFCONFIG_OPTION_SET_DOWN        (1 << 5)
#define IFCONFIG_OPTION_SET_MTU         (1 << 6)

#define NETSTAT_ENTRY_SIZE 120
#define MAX_NETSTAT_ENTRY (NETSTAT_ENTRY_SIZE * (LWIP_NUM_SOCKETS + 4))

#define PRINT_BUF_LEN   1024
#define MAX_MACADDR_STRING_LENGTH    18 /* including NULL */

#define CONVERT_STRING_TO_HEX(_src, _dest)    \
{                                           \
    const char *_srcString = (char *)_src;    \
    _dest = 0;                                  \
    while (*_srcString)                         \
    {                                           \
        _dest = (_dest << 4) & 0xFF;            \
        if ((*_srcString >= 48) && (*_srcString <= 57))    /* between 0 to 9 */  \
            _dest |= (unsigned char)(*_srcString - 48);                     \
        else if ((*_srcString >= 65 && *_srcString <= 70)) /* between A to F */  \
            _dest |= (unsigned char)((*_srcString - 65) + 10);              \
        else if ((*_srcString >= 97 && *_srcString <= 102))/* between a to f */  \
            _dest |= (unsigned char)((*_srcString - 97) + 10);              \
        else break;                             \
        ++_srcString;                           \
    }                                           \
}

#define ERR_IFCONFIG_STRING_PUT(ret, str)     do                                             \
{                                                                                            \
    (ret) = snprintf_s(ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,                 \
        PRINT_BUF_LEN - ifconfig_cmd->print_len,                                             \
        ((PRINT_BUF_LEN - ifconfig_cmd->print_len) - 1), (str));                            \
    if (((ret) > 0) && ((unsigned int)(ret) < (PRINT_BUF_LEN - ifconfig_cmd->print_len)))   \
        ifconfig_cmd->print_len += (unsigned int)(ret);                                      \
} while(0)

struct ifconfig_option {
    char            iface[IFNAMSIZ];
    unsigned int    option;
    unsigned int    ip_addr;
    unsigned int    netmask;
    unsigned int    gw;
    unsigned char   ethaddr[6];
    unsigned short  mtu;
    /* when using telnet, printf to the telnet socket will result in system  */
    /* deadlock. So we cahe the prinf data to a buf, and when the tcpip      */
    /* callback returns, then printf the data out to the telnet socket       */
    sys_sem_t       cb_completed;
    char            cb_print_buf[PRINT_BUF_LEN];
    unsigned int    print_len;
};

struct netstat_data {
    s8_t *netstat_out_buf;
    int netstat_out_buf_len;
    int netstat_out_buf_updated_len;
    sys_sem_t cb_completed;
};

struct if_cmd_data {
  char *if_name;
  err_t err;
  sys_sem_t cb_completed;
};

LWIP_STATIC int print_netif(struct netif *netif, char *print_buf, unsigned int buf_len)
{
    int i,ret;
    char *tmp = print_buf;

    if(netif->link_layer_type == LOOPBACK_IF){
      ret = snprintf_s(tmp, buf_len, (buf_len-1), "%s\t", netif->name);
    }
    else {
      ret = snprintf_s(tmp, buf_len, (buf_len-1), "%s%u\t", netif->name, netif->num);
    }
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len-1), "ip:%s ", ipaddr_ntoa(&netif->ip_addr));
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len-1), "netmask:%s ", ipaddr_ntoa(&netif->netmask));
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len-1), "gateway:%s\n", ipaddr_ntoa(&netif->gw));
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len-1), "\tHWaddr ");
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    for(i = 0; i < netif->hwaddr_len - 1; i++)
    {
        ret = snprintf_s(tmp, buf_len, (buf_len-1), "%02x:", netif->hwaddr[i]);
        if((ret <= 0) || ((unsigned int)ret >= buf_len))
            goto out;
        tmp += ret;
        buf_len -= (unsigned int)ret;
    }

    ret = snprintf_s(tmp, buf_len, (buf_len-1), "%02x", netif->hwaddr[i]);
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;


    ret = snprintf_s(tmp, buf_len, (buf_len-1), " MTU:%d %s", netif->mtu,
        netif->flags&NETIF_FLAG_UP?"Runing":"Stop");
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    if(netif_default == netif && netif_is_up(netif))
    {
      ret = snprintf_s(tmp, buf_len, (buf_len-1), " %s", "Default");
      if((ret <= 0) || ((unsigned int)ret >= buf_len))
          goto out;
      tmp += ret;
      buf_len -= (unsigned int)ret;
    }

    ret = snprintf_s(tmp, buf_len, (buf_len-1), " %s\n",
        netif->flags&NETIF_FLAG_LINK_UP?"Link UP":"Link Down");
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;

out:
    return (int)(tmp - print_buf);
}

LWIP_STATIC void lwip_ifconfig_show_internal(void *arg)
{
    struct netif *netif = NULL;
    struct ifconfig_option *ifconfig_cmd = (struct ifconfig_option *)arg;
    int ret;

    if(netif_list == NULL)
    {
        ret = snprintf_s(ifconfig_cmd->cb_print_buf, PRINT_BUF_LEN - ifconfig_cmd->print_len,
                  ((PRINT_BUF_LEN - ifconfig_cmd->print_len) -1), "Device not init\n");
        if((ret > 0) && ((unsigned int)ret < (PRINT_BUF_LEN - ifconfig_cmd->print_len)))
            ifconfig_cmd->print_len += (unsigned int)ret;

        sys_sem_signal(&ifconfig_cmd->cb_completed);
        return;
    }

    if(ifconfig_cmd->iface[0] == '\0')
    {
        /* display all netif */
        for(netif = netif_list; netif != NULL; netif = netif->next) {
            ret = print_netif(netif,
                ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,
                PRINT_BUF_LEN - ifconfig_cmd->print_len);
            ifconfig_cmd->print_len += (unsigned int)ret;
        }
    }
    else
    {
        netif = netif_find(ifconfig_cmd->iface);
        if(netif == NULL)
        {
            ret = snprintf_s(ifconfig_cmd->cb_print_buf+ ifconfig_cmd->print_len, (PRINT_BUF_LEN - ifconfig_cmd->print_len),
                ((PRINT_BUF_LEN - ifconfig_cmd->print_len) - 1), "Device not found\n");
            if((ret > 0) && ((unsigned int)ret < (PRINT_BUF_LEN - ifconfig_cmd->print_len)))
                ifconfig_cmd->print_len += (unsigned int)ret;

            sys_sem_signal(&ifconfig_cmd->cb_completed);
            return;
        }

        ret = print_netif(netif,
            ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,
            PRINT_BUF_LEN - ifconfig_cmd->print_len);
        ifconfig_cmd->print_len += (unsigned int)ret;
    }
    sys_sem_signal(&ifconfig_cmd->cb_completed);
}

LWIP_STATIC void lwip_ifconfig_internal(void *arg)
{
    struct ifconfig_option *ifconfig_cmd = NULL;
    struct netif *netif = NULL;
    ip_addr_t ip_addr;
    ip_addr_t netmask;
    ip_addr_t gw;
    unsigned short  mtu;
    struct netif *loc_netif = NULL;
    int ret;

    ifconfig_cmd = (struct ifconfig_option *)arg;
    netif = netif_find(ifconfig_cmd->iface);
    if(netif == NULL)
    {
        ERR_IFCONFIG_STRING_PUT(ret, "Device not found\n");
        goto out;
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_UP)
    {
        (void)netif_set_up(netif);
        goto out;
    }
    else if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_DOWN)
    {
        (void)netif_set_down(netif);
        goto out;
    }

    if ((ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP) ||
         (ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK) ||
         (ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW))
    {
        (void)netif_set_down(netif);
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP)
    {
        ip_addr.addr = ifconfig_cmd->ip_addr;
        /* check the address is not multicast/broadcast/0/loopback */
        if (ip_addr_ismulticast(&ip_addr) || ip_addr_isbroadcast(&ip_addr, netif)
            || (ip_addr.addr == IPADDR_ANY) || ip_addr_isloopback(&ip_addr)) /*lint !e506*/
        {
            ERR_IFCONFIG_STRING_PUT(ret, "Don't set ip as a multicast/broadcast/0/loopback address!\n");
            goto out;
        }

        /* reset gateway if new and previous ipaddr not in same net */
        if(!addr_netcmp(ip_addr.addr, netif->ip_addr.addr, netif->netmask.addr))
        {
            ip_addr_set_zero(&netif->gw);
            if (netif == netif_default)
                netif_set_default(NULL);
        }

        /* lwip disallow two netif sit in same net at the same time */
        loc_netif = netif_list;
        while (loc_netif != NULL) {
            if (loc_netif == netif) {
                loc_netif = loc_netif->next;
                continue;
            }
            if(ip_addr_cmp(&netif->netmask, &loc_netif->netmask) &&
                addr_netcmp(loc_netif->ip_addr.addr, ip_addr.addr, netif->netmask.addr)) {
                ERR_IFCONFIG_STRING_PUT(ret, "Duplicate network!\n");
                goto out;
            }
            loc_netif = loc_netif->next;
        }

#if LWIP_DHCP
        if (netif->dhcp && netif->dhcp->state != DHCP_OFF)
        {
            (void)netif_dhcp_off(netif);
        }
#endif
        netif_set_ipaddr(netif, &ip_addr);
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK)
    {
        netmask.addr = ifconfig_cmd->netmask;
#if LWIP_DHCP
        if (netif->dhcp && netif->dhcp->state != DHCP_OFF)
        {
            (void)netif_dhcp_off(netif);
        }
#endif
        /* check data valid */
        if (!ip4_addr_netmask_valid(netmask.addr)) {
            ERR_IFCONFIG_STRING_PUT(ret, "Data invalid!\n");
            goto out;
        }
        if (netif->netmask.addr != netmask.addr) {
        /* lwip disallow two netif sit in same net at the same time */
            loc_netif = netif_list;
            while (loc_netif != NULL) {
                if (loc_netif == netif) {
                    loc_netif = loc_netif->next;
                    continue;
                }
                if(ip_addr_cmp(&loc_netif->netmask, &netmask) &&
                    addr_netcmp(loc_netif->ip_addr.addr,
                    netif->ip_addr.addr, netmask.addr)){
                    ERR_IFCONFIG_STRING_PUT(ret, "Duplicate network!\n");
                    goto out;
                }
                loc_netif = loc_netif->next;
            }
            netif_set_netmask(netif, &netmask);
            /* check if gateway still reachable */
            if (!addr_netcmp(netif->gw.addr,
                netif->ip_addr.addr, netmask.addr))
            {
                ip_addr_set_zero(&(netif->gw));
                if (netif == netif_default)
                    netif_set_default(NULL);
            }
        }
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW)
    {
        netif_set_hwaddr(netif, ifconfig_cmd->ethaddr, 6);
    }

    if ((ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP) ||
         (ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK) ||
         (ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW))
    {
        (void)netif_set_up(netif);
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_GW)
    {
        gw.addr = ifconfig_cmd->gw;

        /* check the address multicast/0/loopback */
        if (ip_addr_ismulticast(&gw) || ip_addr_isbroadcast(&gw, netif)
            || (gw.addr == IPADDR_ANY) || ip_addr_isloopback(&gw)) /*lint !e506*/
        {
            ERR_IFCONFIG_STRING_PUT(ret, "Don't set gateway as a multicast/broadcast/0/loopback address!\n");
            goto out;
        }

        /* check if reachable */
        if(!addr_netcmp(gw.addr, netif->ip_addr.addr, netif->netmask.addr))
        {
            ERR_IFCONFIG_STRING_PUT(ret, "The address is unreachable!\n");
            goto out;
        }

        if (netif_default != netif)
        {
            if (netif_default)
            {
                ip_addr_set_zero(&netif_default->gw);
            }
            netif_set_default(netif);
        }

#if LWIP_DHCP
        if (netif->dhcp && netif->dhcp->state != DHCP_OFF)
        {
            (void)netif_dhcp_off(netif);
        }
#endif
        netif_set_gw(netif, &gw);
    }

    if(ifconfig_cmd->option & IFCONFIG_OPTION_SET_MTU)
    {
        mtu = ifconfig_cmd->mtu;
        if (netif_set_mtu(netif, mtu) != ERR_OK)
        {
            ERR_IFCONFIG_STRING_PUT(ret, "Invalid arguments:mtu should be in [68, 1500]\n");
        }
    }
out:
    sys_sem_signal(&ifconfig_cmd->cb_completed);
}


void lwip_printsize(size_t  size)
{
    static const char *SIZES[] = { "B", "KB", "MB", "GB" };
    size_t divis = 0;
    size_t rem = 0;

    while ((size >= 1024) && (divis < ((sizeof SIZES / sizeof(char *)) - 1)))
    {
        rem = (size % 1024);
        divis++;
        size /= 1024;
    }

    /*lint -e661*/
    PRINTK("(%.1f %s) \r\n", (float)size + (float)rem / 1024.0, SIZES[divis]);
    /*lint +e661*/
}

LWIP_STATIC void lwip_ifconfig_usage(const char * cmd)
{
    PRINTK("Usage:"\
        "\n%s -a [Interface <address>] [netmask <address>] [gateway <address>]"\
        "[hw ether <address>] [mtu <size>] [up | down]\n",
        cmd);
}

/*lint -e838*/
u32_t lwip_ifconfig(int argc, char **argv)
{
    int i = 0;
    static struct ifconfig_option ifconfig_cmd;
    unsigned int stat_err_cnt;
    unsigned int stat_drop_cnt;
    unsigned int stat_rx_or_tx_cnt;
    unsigned int stat_rx_or_tx_bytes;
    err_t        ret;
#if LWIP_ARP
    unsigned int old_ipaddr;
    err_t        err;
    struct netif *inp = NULL;
#endif

    if(!tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return 2;
    }
    /* To support "ifconfig -a" command
         RX packets:XXXX errors:X dropped:X overruns:X bytes:XXXX (Human readable format)
         TX packets:XXXX errors:X dropped:X overruns:X bytes:XXXX (Human readable format)

         Below is assumed for 'overrun' stat.
         Linux Kernel:
                RX: FIFO overrun
                    Data structure: net_device->stats->rx_fifo_errors
                    Flag which is marked when FIFO overrun: ENRSR_FO

                Function: ei_receive->ENRSR_FO

                TX: A "FIFO underrun" occurred during transmit.
                    Data structure: net_device->stats->tx_fifo_errors
                    Flag which is marked when FIFO underrun: ENTSR_FU

                Function: ei_tx_intr->ENTSR_FU

        LWIP:
            So in our case,
            while receiving a packet RX case, if the buffer is full (trypost - it is sys_mbox_trypost)
            the error will be returned, we can consider that an overflow has happend.
            So this can be RX overrun.

            But while transmitting a packet TX case, underrun cannot happen because it block on the
            message Q if it is full (NOT trypost - it is sys_mbox_post). So TX overrun is always 0.
    */
    if (argc)
    {
        if (strcmp("-a", argv[0]) == 0)
        {
#if LWIP_STATS
            stat_rx_or_tx_cnt     = lwip_stats.ip.recv;
            stat_err_cnt          = (lwip_stats.ip.ip_rx_err
                                                        + lwip_stats.ip.lenerr
                                                        + lwip_stats.ip.chkerr
                                                        + lwip_stats.ip.opterr
                                                        + lwip_stats.ip.proterr);
            stat_drop_cnt         = (lwip_stats.ip.drop + lwip_stats.link.link_rx_drop);
            stat_rx_or_tx_bytes = lwip_stats.ip.ip_rx_bytes;

            PRINTK("RX packets:%u\t errors:%u\t dropped:%u\t overrun:%d\t bytes:%u ",
            stat_rx_or_tx_cnt,
            stat_err_cnt,
            stat_drop_cnt,
            lwip_stats.ip.link_rx_overrun,
            stat_rx_or_tx_bytes);

            /* Print in Human readable format of the incoming bytes */
            lwip_printsize(lwip_stats.ip.ip_rx_bytes);


            stat_rx_or_tx_cnt     = (lwip_stats.ip.fw + lwip_stats.ip.xmit);
            stat_err_cnt          = (lwip_stats.ip.rterr + lwip_stats.ip.ip_tx_err);
            stat_drop_cnt         = lwip_stats.link.link_tx_drop; /* IP layer drop stat param is not maintained, failure at IP is considered in 'errors' stat */
            stat_rx_or_tx_bytes   = lwip_stats.ip.ip_tx_bytes;

            PRINTK("TX packets:%u\t errors:%u\t dropped:%u\t overrun:0\t bytes:%u",
                stat_rx_or_tx_cnt,
                stat_err_cnt,
                stat_drop_cnt,
                stat_rx_or_tx_bytes);

            /* Print in Human readable format of the outgoing bytes */
            lwip_printsize(lwip_stats.ip.ip_tx_bytes);
#endif /* LWIP_STATS */
            return 0;
        }
    }

    (void)memset_s(&ifconfig_cmd, sizeof(ifconfig_cmd), 0, sizeof(ifconfig_cmd));
    if (sys_sem_new(&ifconfig_cmd.cb_completed, 0) != ERR_OK) {
        PRINTK("%s: sys_sem_new fail\n", __FUNCTION__);
        return 1;
    }

    i        = 0;
    /* Get the interface */
    if(argc > 0)
    {
        if (strlen(argv[i]) < IFNAMSIZ)
        {
            if (strncpy_s(ifconfig_cmd.iface, IFNAMSIZ, argv[i], (strlen(argv[i]))) != 0 ) {
              sys_sem_free(&ifconfig_cmd.cb_completed);
              return 1;
            }
            ifconfig_cmd.iface[IFNAMSIZ-1] = '\0';
        }
        else
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : interface name is too big");
            return 0;
        }
        i++;
        argc--;
        if(argc == 0)
        {
            /* no more arguments, show the interface state. */
            if((ret = tcpip_callback(lwip_ifconfig_show_internal, &ifconfig_cmd)) != ERR_OK)
            {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
                return 1;
            }
            (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
            sys_sem_free(&ifconfig_cmd.cb_completed);
            ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
            PRINTK("%s", ifconfig_cmd.cb_print_buf);
            return 0;
        }
    }
    else
    {
        /* no more arguments, show all the interface state. */
        if((ret = tcpip_callback(lwip_ifconfig_show_internal, &ifconfig_cmd)) != ERR_OK)
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);

        return 0;
    }

    /* ifup/ifdown */
    if(strcmp("up", argv[i]) == 0)
    {
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_UP;
        /* setup the interface, other arguments is ignored. */
        if((ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd)) != ERR_OK)
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);
        return 0;
    }
    else if(strcmp("down", argv[i]) == 0)
    {
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_DOWN;
        /* setdown the interface, other arguments is ignored. */
        if((ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd)) != ERR_OK)
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);
        return 0;
    }

    /* check if set the ip address. */
#if LWIP_ARP
    inp = netif_find(ifconfig_cmd.iface);
    if (inp == NULL) {
        sys_sem_free(&ifconfig_cmd.cb_completed);
        PRINTK("ifconfig : interface %s not found",ifconfig_cmd.iface);
        return 1;
    }
    old_ipaddr = ipaddr_addr(ipaddr_ntoa(&inp->ip_addr));
#endif
    ifconfig_cmd.ip_addr = ipaddr_addr(argv[i]);
    if(ifconfig_cmd.ip_addr != IPADDR_NONE)
    {
        /* set the ip address */
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_IP;
        i++;
        argc--;
    }
    while(argc > 0)
    {
        /* if set netmask */
        if(strcmp("netmask", argv[i]) == 0 && (argc > 1) &&
            (ipaddr_addr(argv[i+1]) != IPADDR_NONE))
        {
            ifconfig_cmd.netmask = ipaddr_addr(argv[i+1]);
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_NETMASK;
            i += 2;
            argc -= 2;
        }
        /* if set gateway */
        else if(strcmp("gateway", argv[i]) == 0 && (argc > 1) &&
            (ipaddr_addr(argv[i+1]) != IPADDR_NONE))
        {
            ifconfig_cmd.gw = ipaddr_addr(argv[i+1]);
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_GW;
            i += 2;
            argc -= 2;
        }
        /* if set HWaddr */
        /*lint -e561*/
        else if(strcmp("hw", argv[i]) == 0 && argc > 2 &&
            strcmp("ether", argv[i+1]) == 0 )
        {
            char *digit = NULL;
            u32_t macaddrlen = strlen(argv[i+2]) + 1;
            char tmpStr[MAX_MACADDR_STRING_LENGTH];
            char *tmpStr1 = NULL;
            char *saveptr = NULL;
            int j;

            if(macaddrlen != MAX_MACADDR_STRING_LENGTH)
            {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : wrong MAC address format\n");
                return 1;
            }

            if (strncpy_s(tmpStr, MAX_MACADDR_STRING_LENGTH, argv[i+2], macaddrlen - 1) != 0) {
              sys_sem_free(&ifconfig_cmd.cb_completed);
              return 1;
            }

            for(j = 0, tmpStr1 = tmpStr; j < 6; j++, tmpStr1=NULL)
            {
                digit = strtok_r(tmpStr1, ":", &saveptr);

                if((digit == NULL) || (strlen(digit) > 2))
                {
                    sys_sem_free(&ifconfig_cmd.cb_completed);
                    PRINTK("ifconfig : wrong MAC address format\n");
                    return 1;
                }

                CONVERT_STRING_TO_HEX(digit, ifconfig_cmd.ethaddr[j]);
            }
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_HW;
            i += 3;
            argc -= 3;
        }
        /*lint +e561*/
        /* if set mtu */
        else if(strcmp("mtu", argv[i]) == 0 && (argc > 1) &&
            (atoi(argv[i+1]) != 0))
        {
            ifconfig_cmd.mtu = atoi(argv[i+1]);
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_MTU;
            i += 2;
            argc -= 2;
        }
        else
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            goto ifconfig_error;
        }
    }

#if LWIP_ARP

    /* Create the semaphore for ip conflict detection. */
    if (sys_sem_new(&ip_conflict_detect, 0) != ERR_OK) {
        PRINTK("%s: sys_sem_new fail\n", __FUNCTION__);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        return 1;
    }
#endif
    if((ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd)) != ERR_OK)
    {
        sys_sem_free(&ifconfig_cmd.cb_completed);
#if LWIP_ARP
        sys_sem_free(&ip_conflict_detect);
#endif
        PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
        return 1;
    }
    (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
    ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
    PRINTK("%s", ifconfig_cmd.cb_print_buf);

#if LWIP_ARP
    /* Pend 2 seconds for waiting the arp reply if the ip is already in use.*/
    err = sys_arch_sem_wait(&ip_conflict_detect, DUP_ARP_DETECT_TIME);
    sys_sem_free(&ip_conflict_detect);

    if (err < 0)
    {
        /* The result either conflict nor timeout. */
        PRINT_ERR("%s: semaphore pend error [0x%x].\n", __FUNCTION__, err);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        return 1;
    }
    else if (err < DUP_ARP_DETECT_TIME)
    {
        /* Duplicate use of new ip, restore it to the old one. */
        PRINT_ERR("%s: ip conflict!\n", __FUNCTION__);
        ifconfig_cmd.ip_addr = old_ipaddr;
        if((ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd)) !=ERR_OK)
        {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN -1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);

        return 1;
    }
#endif
    sys_sem_free(&ifconfig_cmd.cb_completed);
    return 0;

ifconfig_error:
    lwip_ifconfig_usage("ifconfig");
    return 1;
}
/*lint +e838*/
#ifdef LOSCFG_SHELL
/*lint -e19*/
SHELLCMD_ENTRY(ifconfig_shellcmd, CMD_TYPE_EX, "ifconfig", XARGS, (CMD_CBK_FUNC)lwip_ifconfig);
/*lint +e19*/
#endif /* LOSCFG_SHELL */
/* add arp entry to arp cache */
#define ARP_OPTION_ADD      1
/* delete arp entry to arp cache */
#define ARP_OPTION_DEL      2
/* print all arp entry in arp cache */
#define ARP_OPTION_SHOW     3

struct arp_option {
    /* see the ARP_OPTION_ above */
    int             option;
    /* descriptive abbreviation of network interface */
    char            iface[IFNAMSIZ];
    /* ip addr */
    unsigned int    ipaddr;
    /* hw addr */
    unsigned char            ethaddr[6];
    /* when using telnet, printf to the telnet socket will result in system  */
    /* deadlock.so don't do it.cahe the data to prinf to a buf, and when     */
    /* callback returns, then printf the data out to the telnet socket       */
    sys_sem_t       cb_completed;
    char            cb_print_buf[PRINT_BUF_LEN];
    int             print_buf_len;
};

LWIP_STATIC void lwip_arp_show_internal(struct netif *netif, char *printf_buf, unsigned int buf_len)
{
    u8_t state, i, num;
    int ret;
    char *name = NULL;
    char *tmp = printf_buf;
    ret = snprintf_s(tmp, buf_len, (buf_len-1), "%-24s%-24s%-24s\n","Address", "HWaddress", "Iface");
    if((ret <= 0) || ((unsigned int)ret >= buf_len))
        return;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    if(netif != NULL) {
        for(i = 0; i < ARP_TABLE_SIZE; ++i) {
            state = arp_table[i].state;
            if(state == ETHARP_STATE_STABLE && arp_table[i].netif) {
                name = arp_table[i].netif->name;
                num = arp_table[i].netif->num;
                if(strncmp(name, netif->name, IFNAMSIZ) != 0 || num != netif->num) {
                    continue;
                }
                ret = snprintf_s(tmp, buf_len, (buf_len-1), "%-24s%02X:%02X:%02X:%02X:%02X:%02X       %s%u\n",
                        ipaddr_ntoa(&arp_table[i].ipaddr),
                        arp_table[i].ethaddr.addr[0], arp_table[i].ethaddr.addr[1],
                        arp_table[i].ethaddr.addr[2], arp_table[i].ethaddr.addr[3],
                        arp_table[i].ethaddr.addr[4], arp_table[i].ethaddr.addr[5],
                        name, num);
                if((ret <= 0) || ((unsigned int)ret >= buf_len))
                    return;
                tmp += ret;
                buf_len -= (unsigned int)ret;
            }
        }
    }else {
        for(i = 0; i < ARP_TABLE_SIZE; ++i) {
            state = arp_table[i].state;
            if(state == ETHARP_STATE_STABLE && arp_table[i].netif) {
                ret = snprintf_s(tmp, buf_len, (buf_len-1), "%-24s%02X:%02X:%02X:%02X:%02X:%02X       %s%u\n",
                        ipaddr_ntoa(&arp_table[i].ipaddr),
                        arp_table[i].ethaddr.addr[0], arp_table[i].ethaddr.addr[1],
                        arp_table[i].ethaddr.addr[2], arp_table[i].ethaddr.addr[3],
                        arp_table[i].ethaddr.addr[4], arp_table[i].ethaddr.addr[5],
                        arp_table[i].netif->name, arp_table[i].netif->num);
                if((ret <= 0) || ((unsigned int)ret >= buf_len))
                    return;
                tmp += ret;
                buf_len -= (unsigned int)ret;
            }
        }
    }
}

LWIP_STATIC void lwip_arp_internal(void *arg)
{
    struct arp_option *arp_cmd = (struct arp_option *)arg;
    struct netif *netif = NULL;
    struct eth_addr ethaddr;
    ip_addr_t ipaddr;
    err_t ret = 0;
    bool specify_iface = true;
    int type = 0;

    if(arp_cmd->iface[0] == 'd' && arp_cmd->iface[1] == 'e')
    {
        specify_iface = false;
    }
    else
    {
        /* find the specified netif by it's name */
        netif = netif_find(arp_cmd->iface);
        if (netif == NULL)
        {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "No such device\n");
            goto out;
        }
    }

    type = arp_cmd->option;
    switch(type) {
        case ARP_OPTION_SHOW:
            if(specify_iface == true) {
                lwip_arp_show_internal(netif, arp_cmd->cb_print_buf, PRINT_BUF_LEN);
            }else {
                lwip_arp_show_internal(NULL, arp_cmd->cb_print_buf, PRINT_BUF_LEN);
            }
            break;

        case ARP_OPTION_ADD:
            ipaddr.addr = arp_cmd->ipaddr;
            (void)memcpy_s(ethaddr.addr, sizeof(ethaddr.addr), arp_cmd->ethaddr, 6);
            if(specify_iface == true) {
                /*lint -e613*/
                if(ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))) {//If  in the same subnet
                /*lint +e613*/
                    ret = etharp_update_arp_entry(netif, &ipaddr, &ethaddr, ETHARP_FLAG_TRY_HARD);
                }else {
                    (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Network is unreachable\n");
                    sys_sem_signal(&arp_cmd->cb_completed);
                    return;
                }
            }else {
                for(netif = netif_list; netif != NULL; netif = netif->next) {
                    if(ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))) {//If  in the same subnet
                        ret = etharp_update_arp_entry(netif, &ipaddr, &ethaddr, ETHARP_FLAG_TRY_HARD);
                        if(ret == ERR_OK) {
                            /*only can add success one time*/
                            break;
                        }
                    }
                    /*The netif is last netif and cannot add this arp entry on any netif*/
                    if(netif->next == NULL) {
                        (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Network is unreachable\n");
                        sys_sem_signal(&arp_cmd->cb_completed);
                        return;
                    }
                }
            }
            break;

        case ARP_OPTION_DEL:
            ipaddr.addr = arp_cmd->ipaddr;
            (void)memcpy_s(ethaddr.addr, sizeof(ethaddr.addr), arp_cmd->ethaddr, 6);
            if(specify_iface == true) {
                ret = etharp_delete_arp_entry(netif, &ipaddr);
            }else {
                for(netif = netif_list; netif != NULL; netif = netif->next) {
                    ret = etharp_delete_arp_entry(netif, &ipaddr);
                    if(ret == ERR_OK) {
                        /*only can del success one time*/
                        break;
                    }
                }
            }
            break;

        default:
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Error\n");
            goto out;
        }

out:
    if(type == ARP_OPTION_ADD || type == ARP_OPTION_DEL) {
        if(ret == ERR_MEM) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Out of memory error\n");
        }else if(ret == ERR_ARG) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Illegal argument\n");
        }else {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN-1), "Successed\n");
        }
    }

    sys_sem_signal(&arp_cmd->cb_completed);
}


LWIP_STATIC void lwip_arp_usage(const char * cmd)
{
    PRINTK("Usage:"\
        "\n%s"
        "\n%s [-i IF] -s IPADDR HWADDR"\
        "\n%s [-i IF] -d IPADDR\n",
        cmd, cmd, cmd);
}

u32_t lwip_arp(int argc, char **argv)
{
    int i;
    struct arp_option arp_cmd;
    err_t ret;

    (void)memset_s(&arp_cmd, sizeof(struct arp_option), 0, sizeof(struct arp_option));
    if(!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    arp_cmd.iface[0] = 'd';
    arp_cmd.iface[1] = 'e';
    arp_cmd.iface[2] = '0';
    arp_cmd.option = ARP_OPTION_SHOW;
    arp_cmd.print_buf_len = 0;
    if (sys_sem_new(&arp_cmd.cb_completed, 0) != ERR_OK) {
        PRINTK("%s: sys_sem_new fail\n", __FUNCTION__);
        return 1;
    }

    i  = 0;
    while(argc > 0) {
        if(strcmp("-i", argv[i]) == 0 && (argc > 1)) {
            /* get the network interface's name */
            if (strlen(argv[i]) < IFNAMSIZ) {
                if(strncmp(argv[i+1], "lo", strlen("lo")) == 0) {
                    PRINTK("Illegal operation\n");
                    goto arp_error;
                }
                if(strncpy_s(arp_cmd.iface, IFNAMSIZ, argv[i+1], (sizeof(arp_cmd.iface) - 1)) != 0) {
                    PRINTK("bad parameter\n");
                    goto arp_error;
                }
                arp_cmd.iface[IFNAMSIZ-1] = '\0';
            }else {
                PRINTK("Iface name is big \n");
                goto arp_error;
            }
            i += 2;
            argc -= 2;
        }
        else if(strcmp("-d", argv[i]) == 0 && (argc > 1)) {
            /* arp delete */
            arp_cmd.option = ARP_OPTION_DEL;
            arp_cmd.ipaddr = inet_addr(argv[i+1]);

            if(arp_cmd.ipaddr == IPADDR_NONE) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            i += 3;
            argc -= 3;
        }
        else if(strcmp("-s", argv[i]) == 0 && (argc > 2)) {
            /* arp add */
            char *digit = NULL;
            u32_t macaddrlen = strlen(argv[i+2]) + 1;
            char tmpStr[MAX_MACADDR_STRING_LENGTH];
            char *tmpStr1 = NULL;
            char *saveptr1 = NULL;
            char* temp = NULL;
            int j;

            arp_cmd.option = ARP_OPTION_ADD;
            arp_cmd.ipaddr = inet_addr(argv[i+1]);

            /*lint -e561*/
            if(arp_cmd.ipaddr == IPADDR_NONE ) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            /*cannot add an arp entry of 127.*.*.* */
            if((arp_cmd.ipaddr & (u32_t)0x0000007fUL) == (u32_t)0x0000007fUL) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            if(macaddrlen != MAX_MACADDR_STRING_LENGTH) {
                PRINTK("Wrong MAC address length\n");
                goto arp_error;
            }

            if (strncpy_s(tmpStr, MAX_MACADDR_STRING_LENGTH, argv[i+2], macaddrlen) != 0) {
                goto arp_error;
            }

            for(j = 0, tmpStr1 = tmpStr; j < 6; j++, tmpStr1 = NULL) {
                digit = strtok_r(tmpStr1, ":", &saveptr1);
                if((digit == NULL) || (strlen(digit) > 2)) {
                    PRINTK("MAC address is not correct\n");
                    goto arp_error;
                }

                for(temp = digit; *temp != '\0'; temp++) {
                    if(!isxdigit(*temp)) {
                        PRINTK("MAC address is not correct\n");
                        goto arp_error;
                    }
                }

                CONVERT_STRING_TO_HEX(digit, arp_cmd.ethaddr[j]);
            }
            /*lint +e561*/

            i += 3;
            argc -= 3;
        }else {
            goto arp_error;
        }
    }

    if((ret = tcpip_callback(lwip_arp_internal, &arp_cmd))!= ERR_OK)
    {
        PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__,__LINE__,ret);
        sys_sem_free(&arp_cmd.cb_completed);
        return 1;
    }
    (void)sys_arch_sem_wait(&arp_cmd.cb_completed, 0);
    sys_sem_free(&arp_cmd.cb_completed);
    arp_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
    PRINTK("%s", arp_cmd.cb_print_buf);
    return 0;

arp_error:
    lwip_arp_usage("arp");
    sys_sem_free(&arp_cmd.cb_completed);
    return 1;
}

#ifdef LOSCFG_SHELL
/*lint -e19*/
SHELLCMD_ENTRY(arp_shellcmd, CMD_TYPE_EX, "arp", 1, (CMD_CBK_FUNC)lwip_arp);
/*lint +e19*/
#endif /* LOSCFG_SHELL */

void ifup_internal(void *arg)
{
    struct netif* netif;
    struct if_cmd_data *ifcmd_data;

    ifcmd_data = (struct if_cmd_data *)arg;
    netif = netif_find(ifcmd_data->if_name);
    if (netif == NULL) {
        ifcmd_data->err = ERR_VAL;
    } else {
        (void)netif_set_up(netif);
        ifcmd_data->err = ERR_OK;
    }

    sys_sem_signal(&ifcmd_data->cb_completed);
    return;
}

void ifdown_internal(void *arg)
{
    struct netif *netif = NULL;
    struct if_cmd_data *ifcmd_data = NULL;

    ifcmd_data = (struct if_cmd_data *)arg;
    netif = netif_find(ifcmd_data->if_name);
    if (netif == NULL) {
        ifcmd_data->err = ERR_VAL;
    } else {
        (void)netif_set_down(netif);
        ifcmd_data->err = ERR_OK;
    }

    sys_sem_signal(&ifcmd_data->cb_completed);
    return;
}

#if LWIP_DNS
LWIP_STATIC struct hostent *gethostnameinfo (const char *host)
{
    static struct hostent hostbuf;
    struct hostent *hp;
    size_t hstbuflen;
    char tmphstbuf[1024];
    int res;
    int herr;

    hstbuflen = 1024;

    res = gethostbyname_r (host, &hostbuf, tmphstbuf, hstbuflen,
            &hp, &herr);
    /*  Check for errors.  */
    if (res || hp == NULL)
        return NULL;
    return hp;
}

LWIP_STATIC unsigned int get_hostip(const char *hname)
{
    unsigned int ip=0;

    struct hostent* pent = gethostnameinfo(hname);
    if( NULL==pent || NULL==pent->h_addr )
        return 0;
    (void)memcpy_s( &ip, sizeof(ip), pent->h_addr, 4 );
    return ip;
}
#endif


static int ping_taskid = -1;
static int ping_kill = 0;
#define PING_ZERO_DATA_LEN 8
static void lwip_ping_usage(void)
{
    PRINTK("Usage:"\
        "\n  ping"
        "\n  ping [-n cnt] [-w interval] [-l data_len] destination"
        "\n  ping [-t] [-w interval] destination"
        "\n  ping -k");
    PRINTK("\n  -t means ping forever, user can use -k to stop the forever ping");
}

static int osPingFunc(u32_t destip, u32_t cnt, u32_t interval, u32_t data_len)
{
    int sfd;
    struct sockaddr_in to;
    struct pbuf *pbuf_resp = NULL;
    struct icmp_echo_hdr *iecho = NULL;
    struct icmp_echo_hdr *iecho_resp = NULL;
    struct ip_hdr *iphdr_resp = NULL;
    u32_t iecho_len;
    s16_t ip_hlen;
    u32_t forever;
    u32_t i = 0;
    u32_t succ_cnt = 0;
    u32_t failed_cnt = 0;
    clock_t start_ms = 0, end_ms = 0;
    clock_t timout_ms = 0,timout_end_ms = 0;
    struct pollfd pfd;
    s32_t rtt;
    int ret = 0;
    u32_t  intrvl = 0;
    char * data_buf = NULL;
    BOOL timeout_flag = false;

    iecho_len= sizeof(struct icmp_echo_hdr) + data_len;
    if ((sfd = lwip_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
        perror("Ping socket");
        return -1;
    }
    pbuf_resp = pbuf_alloc(PBUF_RAW, IP_HLEN + sizeof(struct icmp_echo_hdr), PBUF_RAM);
    if (pbuf_resp == NULL)
    {
        PRINTK("Ping: pbuf_resp malloc failed\n");
        ret = -1;
        goto FAILURE;
    }
    iecho = (struct icmp_echo_hdr *)mem_malloc(iecho_len);
    if (iecho == NULL)
    {
        PRINTK("Ping: echo request malloc failed\n");
        ret = -1;
        goto FAILURE;
    }

    to.sin_family = AF_INET;
    to.sin_addr.s_addr = destip; /* already in network order */
    to.sin_port = 0;

    if (data_len > PING_ZERO_DATA_LEN)
    {
        if (memset_s(iecho, sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN, 0, sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN) != 0) {
          goto FAILURE;
        }
        data_buf = (char *)iecho + sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN;
        for (i=0; i<data_len - PING_ZERO_DATA_LEN; i++){
            *(data_buf + i) = i + 0x10;
        }
    }
    else
    {
        if (memset_s(iecho, sizeof(struct icmp_echo_hdr) + data_len, 0, sizeof(struct icmp_echo_hdr) + data_len) != 0) {
          goto FAILURE;
        }
    }
    iecho->id = htons((u16_t)LOS_CurTaskIDGet());
    ICMPH_TYPE_SET(iecho, (u8_t)ICMP_ECHO);
    forever = (cnt ? 0:1);
    i = 0;
    while (!ping_kill && (forever || (i < cnt)))
    {
        iecho->seqno = htons((u16_t)i);
        iecho->chksum = 0;
        iecho->chksum = inet_chksum((void *)iecho, iecho_len);

        ret = sendto(sfd, iecho, iecho_len, 0, (struct sockaddr *)&to, (socklen_t)sizeof(to));
        if (ret < 0)
        {
            perror("Ping: sending ICMP echo request failed\n");
            goto FAILURE;
        }

        /* capture the start ms to calculate RTT */
        start_ms = clock();

        /* poll for ICMP echo response msg */
        pfd.fd = sfd;

        do {
            pfd.events = POLLIN;
            pfd.revents = 0;
            timeout_flag = false;
            ret = poll(&pfd, 1, LWIP_SHELL_CMD_PING_TIMEOUT);
            if (ret < 0)
            {
                perror("Ping: poll\n");
                goto FAILURE;
            }
            else if (ret == 0)
            {
                /* first type timeout event */
                timeout_flag = true;
                break;
            }

            /* construct timeout event if poll lose efficacy when other host ping us */
            ret = recv(sfd, pbuf_resp->payload, pbuf_resp->len, MSG_DONTWAIT);
            if (ret < 0)
            {
                perror("Ping: recv echo reply failed\n");
                goto FAILURE;
            }

            /* Accessing ip header and icmp header */
            iphdr_resp = pbuf_resp->payload;

            ip_hlen = (IPH_HL(iphdr_resp) << 2);
            if (pbuf_header(pbuf_resp, -ip_hlen))
            {
                /* this failure will never happen, but failure handle is written just to be in safe side */
                PRINTK("Ping : memory management failure\n");
                goto FAILURE;
            }
            iecho_resp = (struct icmp_echo_hdr *)pbuf_resp->payload;
            /* Reverting back pbuf to its original state */
            if (pbuf_header(pbuf_resp, ip_hlen))
            {
                /* this failure will never happen, but failure handle is written just to be in safe side */
                PRINTK("ping : memory management failure\n");
                goto FAILURE;
            }

            if ((iphdr_resp->src.addr != to.sin_addr.s_addr) ||
                ((ICMPH_TYPE(iecho_resp) == ICMP_ECHO) && (iphdr_resp->src.addr == to.sin_addr.s_addr)))
            {
                /* second type timeout event */
                timout_end_ms = clock();
                timout_ms = timout_end_ms - start_ms;
                if (timout_ms < 0)
                {
                    timout_ms += (clock_t)(0x100000000 * 256 /(OS_TIME_TIMER_CLOCK/1000)); /* wraparound */
                }
                timout_ms = LWIP_SHELL_CMD_PING_TIMEOUT - timout_ms;
            }
            else
            {
                timout_ms = 0;
                break;
            }
        }while(timout_ms >= 0);

        /* all timeout events are true timeout */
        if ((timout_ms < 0) || (timeout_flag == true))
        {
            failed_cnt++;
            i++;
            PRINTK("\nPing: destination unreachable ...");
            continue;
        }
        /* capture the end ms to calculate round trip time */
        end_ms = clock();
        rtt = (s32_t)(end_ms -start_ms);
        if(rtt < 0)
        {
            rtt += (s32_t)(0x100000000 * 256 /(OS_TIME_TIMER_CLOCK/1000)); /* wraparound */
        }

        if (iphdr_resp->src.addr == to.sin_addr.s_addr)
        {
            switch (ICMPH_TYPE(iecho_resp))
            {
                case ICMP_ER:
                    /*lint -e559 -e705 */
                    PRINTK("\n[%u]Reply from %s: ", i, inet_ntoa(to.sin_addr));
                    if (rtt > 0){
                        PRINTK("time=%ims ", rtt);
                    } else {
                        PRINTK("time<1ms ");
                    }
                    PRINTK("TTL=%u", iphdr_resp->_ttl);
                    /*lint +e559 +e705 */

                    /* delay 1s for every successful ping */
                    intrvl = interval;
                    do
                    {
                        if (intrvl < 1000)
                        {
                            sys_msleep(intrvl);
                            break;
                        }
                        intrvl -= 1000;
                        sys_msleep(1000);
                        if (ping_kill == 1)
                            break;
                    }
                    while (intrvl > 0);
                    succ_cnt++;
                    break;
                case ICMP_DUR:
                    PRINTK("\nPing: destination host unreachable ...");
                    break;
                case ICMP_SQ:
                    PRINTK("\nPing: source quench ...");
                    break;
                case ICMP_RD:
                    PRINTK("\nPing: redirect ...");
                    break;
                case ICMP_TE:
                    PRINTK("\nPing: time exceeded ...");
                    break;
                case ICMP_PP:
                    PRINTK("\nPing: parameter problem ...");
                    break;
                default :
                    PRINTK("\nPing: unknow error ...");
                    break;
            }
            i++;
        }
    }


    PRINTK("\n--- %s ping statistics ---\n", inet_ntoa(to.sin_addr));
    PRINTK("%u packets transmitted, %u received, %u loss\n", i, succ_cnt, failed_cnt);

FAILURE:
    ping_kill = 0;
    (void)lwip_close(sfd);
    if (pbuf_resp != NULL) {
        (void)pbuf_free(pbuf_resp);
    }
    if (iecho != NULL) {
        mem_free(iecho);
    }
    return ret;
}
static void ping_cmd(unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3)
{
    u32_t destip = p0;
    u32_t count = p1;
    u32_t interval = p2;
    u32_t data_len = p3;
    int ret;

    ret = osPingFunc(destip, count, interval, data_len);
    if (ret < 0) {
        PRINTK("Ping cmd failed due some errors\n");
    }

    ping_taskid = -1;
}

/*lint -e838*/
u32_t osShellPing(int argc, char **argv)
{
    int ret;
    u32_t i = 0;
    u32_t count = 0;
    int count_set = 0;
    u32_t interval = 1000; /* default ping interval */
    u32_t data_len = 48; /* default data length */
    ip_addr_t dst_ipaddr;
    TSK_INIT_PARAM_S stPingTask;

    if(!tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if ((argc < 1) || (argv == NULL))
    {
        PRINTK("Ping: require dest ipaddr at least \n");
        goto ping_error;
    }

    /* could add more param support */
    while (argc > 0) {
        if (strcmp("-n", argv[i]) == 0 && (argc > 1)) {
            ret = atoi(argv[i+1]);
            if (ret <= 0) {
                PRINTK("Ping count should be greater than 0 \n");
                goto ping_error;
            }
            count = ret;
            count_set = 1;
            i += 2;
            argc -= 2;
        } else if (strcmp("-t", argv[i]) == 0) {
            count = 0; /* ping forerver */
            count_set = 1;
            i++;
            argc--;
        } else if (strcmp("-w", argv[i]) == 0) {
            ret = atoi(argv[i+1]);
            if (ret <= 0) {
                PRINTK("Ping inteval should be greater than 0 \n");
                goto ping_error;
            }

            interval = ret;
            i += 2;
            argc -= 2;
        } else if (strcmp("-l", argv[i]) == 0) {
            ret = atoi(argv[i+1]);
            if (ret < 0 || ret > (int)(DEFAULT_UDP_AND_RAW_MAX_SEND_SIZE - sizeof(struct icmp_echo_hdr))) {
                PRINTK("Ping data length error, should be in range of [0, %d] \n", DEFAULT_UDP_AND_RAW_MAX_SEND_SIZE - sizeof(struct icmp_echo_hdr));
                goto ping_error;
            }
            data_len = ret;
            i += 2;
            argc -= 2;
        }
        else if (strcmp("-k", argv[i]) == 0) {
            if (ping_taskid > 0) {
                ping_kill = 1; /* stop the current ping task */
                return LOS_OK;
            } else {
                PRINTK("No ping task running...\n");
                return LOS_NOK;
            }
        } else {
            if (argc == 1) {
               break;
            } else {
               PRINTK("Invalid Ping param\n");
               goto ping_error;
            }
        }
    }

    if (!count_set) {
        count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
    }

    /* initialize dst IP address */
#if LWIP_DNS
    dst_ipaddr.addr = get_hostip(argv[i]);
#else /* LWIP_DNS */
    dst_ipaddr.addr = inet_addr(argv[i]);
#endif /* LWIP_DNS */

    if (dst_ipaddr.addr == IPADDR_NONE || dst_ipaddr.addr == IPADDR_ANY)
    {
        PRINTK("Invalid dest ipaddr: %s\n", argv[i]);
        return LOS_NOK;
    }

    /* start one task if ping forever or ping count greater than 60 */
    if (count == 0 || count > LWIP_SHELL_CMD_PING_RETRY_TIMES) {
        if (ping_taskid > 0) {
            PRINTK("Ping task already running and only support one now\n");
            return LOS_NOK;
        }
        stPingTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;
        stPingTask.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
        stPingTask.pcName = "ping_task";
        stPingTask.usTaskPrio = 8; /* higher than shell */
        stPingTask.uwResved = LOS_TASK_STATUS_DETACHED;
        stPingTask.auwArgs[0] = dst_ipaddr.addr; /* network order */
        stPingTask.auwArgs[1] = count;
        stPingTask.auwArgs[2] = interval;
        stPingTask.auwArgs[3] = data_len;
        ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &stPingTask);
        if (LOS_OK != ret ) {
            PRINTK("ping_task create failed 0x%08x.\n", ret);
            count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
        }else {
            return LOS_OK;
        }
    }

    /* two cases:
     1, ping cout less than LWIP_SHELL_CMD_PING_RETRY_TIMES;
     2, ping task create failed;
    */
    if(osPingFunc(dst_ipaddr.addr, count, interval, data_len) < 0) {
        PRINTK("Ping cmd failed due some errors\n");
    }

    return LOS_OK;
ping_error:
    lwip_ping_usage();
    return LOS_NOK;
}
/*lint +e838*/
#ifdef LOSCFG_SHELL
/*lint -e19*/
SHELLCMD_ENTRY(ping_shellcmd, CMD_TYPE_EX, "ping", XARGS, (CMD_CBK_FUNC)osShellPing);
/*lint +e19*/
#endif /* LOSCFG_SHELL */

u32_t osShellNtpdate(int argc, char **argv)
{
    int server_num;
    struct timeval sttime;
    char* ret = NULL;
    if(!tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if(argc < 1)
    {
        goto usage_return;
    }

    server_num = lwip_sntp_start(argc, argv, &sttime);
    if(server_num >= 0 && server_num < argc) {
        ret = ctime((time_t *)&sttime.tv_sec);
        if (ret != NULL) {
            PRINTK("time server %s: %s\n", argv[server_num], ret);
        } else {
            PRINTK("ctime return null error\n");
        }
    } else {
        PRINTK("no server suitable for synchronization found\n");
    }
    return LOS_OK;
usage_return:
    PRINTK("usage:\n");
    PRINTK("ntpdate [SERVER_IP1] [SERVER_IP2] ...\n");
  return LOS_NOK;
}
#ifdef LOSCFG_SHELL
/*lint -e19*/
SHELLCMD_ENTRY(ntpdate_shellcmd, CMD_TYPE_EX, "ntpdate",  XARGS, (CMD_CBK_FUNC)osShellNtpdate);
/*lint +e19*/
#endif /* LOSCFG_SHELL */

#ifdef LOSCFG_NET_LWIP_SACK_TFTP
static char *TftpError[] =
{
    "TFTP transfer finish\n",
    "Error while creating UDP socket\n",
    "Error while binding to the UDP socket\n",
    "Error returned by lwip_select() system call\n",
    "Error while receiving data from the peer\n",
    "Error while sending data to the peer\n",
    "Requested file is not found\n",
    "This is the error sent by the server when hostname cannot be resolved\n",
    "Input paramters passed to TFTP interfaces are invalid\n",
    "Error detected in TFTP packet or the error received from the TFTP server\n",
    "Error during packet synhronization while sending or unexpected packet is received\n",
    "File size limit crossed, Max block can be 0xFFFF, each block containing 512 bytes\n",
    "File name lenght greater than 256\n",
    "Hostname IP is not valid\n",
    "TFTP server returned file access error\n",
    "TFTP server returned error signifying that the DISK is full to write\n",
    "TFTP server returned error signifying that the file exist\n",
    "The source file name do not exisits\n",
    "Memory allocaion failed in TFTP client\n",
    "File open failed\n",
    "File read error\n",
    "File create error\n",
    "File write error\n",
    "Max time expired while waiting for file to be recived\n",
    "Error when the received packet is less than 4bytes(error lenght) or greater than 512bytes\n",
    "Returned by TFTP server for protocol user error\n",
    "The destination file path length greater than 256\n",
    "Returned by TFTP server for undefined transfer ID\n",
    "IOCTL fucntion failed at TFTP client while setting the socket to non-block\n",
};

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif

u32_t osShellTftp(int argc, char **argv)
{
    u32_t  ulRemoteAddr = IPADDR_NONE;
    u16_t  usTftpServPort = 69;
    u8_t   ucTftpGet = 0;
    s8_t   *szLocalFileName = NULL;
    s8_t   *szRemoteFileName = NULL;
    u32_t  ret;

    int i = 0;

    if(!tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    while(i < argc)
    {
        if(strcmp(argv[i], "-p") == 0)
        {
            ucTftpGet = 0;
            i++;
            continue;
        }

        if(strcmp(argv[i], "-g") == 0)
        {
            ucTftpGet = 1;
            i++;
            continue;
        }

        if(strcmp(argv[i], "-l") == 0 && ((i + 1) < argc))
        {
            szLocalFileName = (s8_t *)argv[i+1];
            i += 2;
            continue;
        }

        if(strcmp(argv[i], "-r") == 0 && ((i + 1) < argc))
        {
            szRemoteFileName = (s8_t *)argv[i+1];
            i += 2;
            continue;
        }

        if((i + 1) == argc)
        {
            ulRemoteAddr = inet_addr(argv[i]);
            break;
        }

        goto usage;
    }

    if(ulRemoteAddr == IPADDR_NONE || szLocalFileName == NULL || szRemoteFileName == NULL)
    {
        goto usage;
    }

    if(ucTftpGet)
        ret = lwip_tftp_get_file_by_filename(ntohl(ulRemoteAddr), usTftpServPort,
            TRANSFER_MODE_BINARY, szRemoteFileName, szLocalFileName);
    else
        ret = lwip_tftp_put_file_by_filename(ntohl(ulRemoteAddr), usTftpServPort,
            TRANSFER_MODE_BINARY, szLocalFileName, szRemoteFileName);

    LWIP_ASSERT("TFTP UNKNOW ERROR!", ret < ARRAY_SIZE(TftpError));
    PRINTK("%s", TftpError[ret]);
    if(ret)
        return LOS_NOK;
    else
        return LOS_OK;
usage:
    PRINTK("usage:\nTransfer a file from/to tftp server\n");
    PRINTK("tftp <-g/-p> -l FullPathLocalFile -r RemoteFile Host\n");
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(tftp_shellcmd, CMD_TYPE_EX, "tftp", XARGS, (CMD_CBK_FUNC)osShellTftp);/*lint !e19*/
#endif /* LOSCFG_SHELL */
#endif /* LOSCFG_NET_LWIP_SACK_TFTP */


#if LWIP_DNS
u32_t osShellDns(int argc, char **argv)
{
    ip_addr_t dns;
    err_t err;
    int i;

    if (0 == tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if(argc == 1 && (strcmp(argv[0], "-a") == 0))
    {
        for(i = 0; i < DNS_MAX_SERVERS; i++)
        {
          err = lwip_dns_getserver((u8_t)i, &dns);
          if (err == ERR_OK) {
              PRINTK("dns%d: %s\n", i+1, ipaddr_ntoa(&dns));
          } else {
              PRINTK("dns: failed\n");
              return LOS_NOK;
          }
        }
        return LOS_OK;
    }
    else if(argc == 2)
    {
        i = atoi(argv[0]);
        if ((i <= 0) || (i > DNS_MAX_SERVERS))
            goto usage;
        dns.addr = ipaddr_addr(argv[1]);
        if(dns.addr == IPADDR_NONE)
        {
            PRINTK("ip address<%s> is wrong\n", argv[i]);
            return LOS_NOK;
        }

        err = lwip_dns_setserver((u8_t)(i - 1), &dns);
        if (err != ERR_OK) {
            PRINTK("dns : failed\n");
            return LOS_NOK;
        }
        return LOS_OK;
    }

usage:
    PRINTK("usage:\n");
    PRINTK("\tdns <1-%d> <IP>\n", DNS_MAX_SERVERS);
    PRINTK("\tdns -a\n");
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
/*lint -e19*/
SHELLCMD_ENTRY(dns_shellcmd, CMD_TYPE_EX, "dns", XARGS, (CMD_CBK_FUNC)osShellDns);
/*lint +e19*/
#endif /* LOSCFG_SHELL */
#endif /* LWIP_DNS */

#if LWIP_PPPOE

u32_t osShellPPPoE(int argc, char **argv)
{
    struct netif *ethif = NULL;
    err_t er_ret;
    if (0 == tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if(argc > 1)
    {
        if (strlen(argv[1]) < IFNAMSIZ)
        {
            ethif = netif_find(argv[1]);
            if (ethif == NULL)
            {
                PRINTK("pppoe : didn't find %s\n", argv[1]);
                return LOS_NOK;
            }
        }
        else
        {
            PRINTK("pppoe : interface name is too big\n");
            return LOS_NOK;
        }

        if (!strncmp(argv[0], "start", strlen("start")))
        {
            int ret = 0;
            if(argc != 4)
            {
                goto usage;
            }

            ret = lwip_pppoe_start(ethif, argv[2], argv[3]);
            if(ret < 0)
            {
                return LOS_NOK;
            }
        }
        else if (!strncmp(argv[0], "stop", strlen("stop")))
        {
            if(argc > 2)
            {
                goto usage;
            }
            if((er_ret = lwip_pppoe_stop(ethif)) != ERR_OK)
            {
                PRINTK("pppoe : lwip_pppoe_stop failed: %d\n",er_ret);
                return LOS_NOK;
            }
        }
        return LOS_OK;
    }
usage:
    PRINTK("usage:\n");
    PRINTK("\tpppoe start [Interface] [Username] [Password]\n");
    PRINTK("\tpppoe stop [Interface]\n");
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(pppoe_shellcmd, CMD_TYPE_EX, "pppoe", XARGS, (CMD_CBK_FUNC)osShellPPPoE);/*lint !e19*/
#endif /* LOSCFG_SHELL */
#endif /* LWIP_PPPOE */


int netstat_get_udp_sendQLen(struct udp_pcb *udppcb, struct pbuf *udpbuf)
{
    int sendLen = -1;
    s16_t offset = 0, len;
    struct ip_hdr *iphdr = NULL;
    struct udp_hdr *udphdr = NULL;

    LWIP_ERROR("netstat_get_udp_sendQLen: NULL pcb received\n", (udppcb != NULL), return -1;);
    LWIP_ERROR("netstat_get_udp_sendQLen: NULL pbuf received\n", (udpbuf != NULL), return -1;);

    len = PBUF_LINK_HLEN;
    if(pbuf_header(udpbuf, -len)){
        goto FUNC_OUT;
    }

    offset += len;

    iphdr = (struct ip_hdr *)udpbuf->payload;

    if(!(ip_addr_cmp(&iphdr->dest, &udppcb->remote_ip)
            && (ip_addr_isany(&udppcb->local_ip) ||
                ip_get_option(udppcb, SOF_BINDNONUNICAST) ||
                ip_addr_cmp(&iphdr->src, &udppcb->local_ip)))) {
        goto FUNC_OUT;
    }
#if LWIP_UDPLITE
    if((IPH_PROTO(iphdr) != IP_PROTO_UDP) && (IPH_PROTO(iphdr) != IP_PROTO_UDPLITE)) {
#else
    if(IPH_PROTO(iphdr) != IP_PROTO_UDP) {
#endif
        goto FUNC_OUT;
    }

    if((ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) != 0)
    {
        goto FUNC_OUT;
    }

    len = IPH_HL(iphdr) * 4;
    if(pbuf_header(udpbuf, -len)) {
        goto FUNC_OUT;
    }

    offset += len;

    udphdr = (struct udp_hdr *)udpbuf->payload;
    if((ntohs(udphdr->dest) == udppcb->remote_port) && (ntohs(udphdr->src) == udppcb->local_port)) {
        sendLen = ntohs(udphdr->len) - UDP_HLEN;
    }

FUNC_OUT:
    (void)pbuf_header(udpbuf, offset);
    return sendLen;
}


int netstat_tcp_sendq(struct tcp_pcb *tpcb)
{
    int retVal = 0;
    struct tcp_seg *useg = NULL;

    LWIP_ERROR("netstat_tcp_sendq: Received NULL pcb\n", (tpcb != NULL), return 0;);

    for (useg = tpcb->unacked; useg != NULL; useg = useg->next){
        retVal = retVal + useg->len;
    }

    return retVal;
}

int netstat_udp_sendq(struct udp_pcb *upcb)
{
    int retLen = 0, ret;
    int arpidx = -1;
    int i;
#if ARP_QUEUEING
    struct etharp_q_entry  *arpq = NULL;
#endif

    LWIP_ERROR("netstat_udp_sendq: Received NULL pcb\n", (upcb != NULL), return 0;);

    for (i = 0; i < ARP_TABLE_SIZE; ++i) {
        if (arp_table[i].state != ETHARP_STATE_EMPTY) {
            if (ip_addr_cmp(&upcb->remote_ip, &arp_table[i].ipaddr)) {
                arpidx = i;
                break;
            }
        }
    }

    if(arpidx >= 0) {
#if ARP_QUEUEING
        for(arpq = arp_table[arpidx].q; arpq != NULL; arpq = arpq->next) {
            ret = netstat_get_udp_sendQLen(upcb, arpq->p);
            if(ret > 0) {
                retLen += ret;
                if (retLen <= 0) { //overflow, set rteLen = -1 to indicate
                    retLen = -1;
                    break;
                }
            }
        }
#else
        ret = netstat_get_udp_sendQLen(arp_table[arpidx].q);
        if(ret > 0) {
            retLen += ret;
            if (retLen <= 0) { //overflow, set rteLen = -1 to indicate
                retLen = -1;
            }
        }
#endif
    }

    return retLen;
}

int netstat_netconn_recvq(struct netconn * conn)
{
    int retVal = 0;

#if LWIP_SO_RCVBUF
    u32_t type;
    if (conn == NULL) {
        return 0;
    }

    type = conn->type;
    switch (type) {
        case NETCONN_TCP:
        case NETCONN_RAW:
        case NETCONN_PKT_RAW:
        case NETCONN_UDP:
            SYS_ARCH_GET((conn->recv_avail + conn->lrcv_left), retVal); /*lint !e40*/
            break;
        default:
            retVal = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
    }
#endif
    return retVal;
}

int netstat_netconn_sendq(struct netconn * conn)
{
    int retVal = 0;
    u32_t type;

    if (conn == NULL) {
        return 0;
    }

    type = conn->type;
    switch (type) {
        case NETCONN_TCP:
            retVal = netstat_tcp_sendq(conn->pcb.tcp);
            break;
        case NETCONN_RAW:
            retVal = 0; /* todo */
        case NETCONN_PKT_RAW:
            retVal = 0; /* always be 0 as frame send to driver directly */
            break;
        case NETCONN_UDP:
            retVal = netstat_udp_sendq(conn->pcb.udp);
            break;
        default:
            retVal = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
    }

    return retVal;
}


void netstat_time_info(struct tcp_pcb* tpcb, u32_t* s_rec)
{
  *s_rec = 0;
#if LWIP_DEBUG_TCP_LEAK
  switch (tpcb->state) {
    case CLOSED:     /* Get the time when pcb was created*/
    case CLOSE_WAIT: /* Get the time when pcb received FIN */
    case LAST_ACK:   /* Get the time when pcb received FIN */
      *s_rec = tpcb->t_misc;
      break;
    default:
      break;
  }
#endif /* LWIP_DEBUG_TCP_LEAK */
}


/*lint -e732*/
void netstat_internal(void *ctx)
{
    struct tcp_pcb *tpcb = NULL;
    struct tcp_pcb_listen *lpcb = NULL;
    struct udp_pcb *upcb = NULL;
    struct raw_pcb *rpcb = NULL;
    s8_t *entry_buf = NULL;
    int entry_buf_len;
    int entry_buf_offset;
    struct netstat_data *ndata = (struct netstat_data *)ctx;
    int iRet;
    s8_t local_ip_port[25] = {0};
    s8_t remote_ip_port[25] = {0};
    int recvQlen = 0;
    int sendQlen = 0;
    u_int proto;
    u8_t netif_name[IFNAMSIZ];
    struct netif* netif = NULL;
    u32_t s_rec = 0;
    entry_buf = ndata->netstat_out_buf;
    entry_buf_len = ndata->netstat_out_buf_len;
    entry_buf_offset = 0;

    if (entry_buf == NULL) {
        goto out;
    }

    iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1),
        "========== total sockets %d ======  unused sockets %d ===  BootTime %u s=======\n", LWIP_NUM_SOCKETS, get_unused_socket_num(), sys_now_second());
    if ((iRet <= 0) || (iRet >= entry_buf_len)) {
        goto out;
    }
    entry_buf_len -= iRet;
    entry_buf_offset += iRet;

#if LWIP_TCP
    if (tcp_active_pcbs != NULL || tcp_bound_pcbs != NULL || tcp_tw_pcbs != NULL || tcp_listen_pcbs.pcbs != NULL) {
        iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "%-8s%-12s%-12s%-24s%-24s%-16s%-8s\n",
          "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "State", "Time");
        if ((iRet <= 0) || (iRet >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= iRet;
        entry_buf_offset += iRet;

        for (tpcb = tcp_active_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));

            iRet = snprintf_s((char*)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char*)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            if (tpcb->state == SYN_RCVD) {
                recvQlen = 0;
                sendQlen = 0;
            } else {
                recvQlen = netstat_netconn_recvq(tpcb->callback_arg);
                sendQlen = netstat_netconn_sendq(tpcb->callback_arg);
            }

            netstat_time_info(tpcb, &s_rec);
            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "%-8s%-12d%-12d%-24s%-24s%-16s%-8u\n",
                      "tcp", recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state], s_rec);
            if ((iRet <= 0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }

        /* For bound PCBs */
        sendQlen = 0;
        recvQlen = 0;

        for (tpcb = tcp_bound_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));

            iRet = snprintf_s((char*)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char*)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            netstat_time_info(tpcb, &s_rec);
            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "%-8s%-12d%-12d%-24s%-24s%-16s%-8u\n",
                      "tcp", recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state], s_rec);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }

        for (tpcb = tcp_tw_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),"%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            recvQlen = netstat_netconn_recvq(tpcb->callback_arg);
            sendQlen = netstat_netconn_sendq(tpcb->callback_arg);

            netstat_time_info(tpcb, &s_rec);
            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "%-8s%-12d%-12d%-24s%-24s%-16s%-8u\n",
                      "tcp", recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state], s_rec);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }

        /* For listen PCBs */
        recvQlen = 0;
        sendQlen = 0;

        for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));

            iRet = snprintf_s((char*)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s:%d", ipaddr_ntoa(&lpcb->local_ip), lpcb->local_port);
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char*)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d", ipaddr_ntoa(&lpcb->remote_ip), 0);
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            recvQlen = netstat_netconn_recvq(lpcb->callback_arg);
            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                      "tcp", recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[lpcb->state]);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }
    }
#endif

#if LWIP_UDP
    if (udp_pcbs != NULL) {
        iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "\n%-8s%-12s%-12s%-24s%-24s\n",
          "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address");
        if ((iRet <= 0) || (iRet >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= iRet;
        entry_buf_offset += iRet;


        for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));

            iRet = snprintf_s((char*)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),"%s:%d", ipaddr_ntoa(&upcb->local_ip), upcb->local_port);
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char*)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d", ipaddr_ntoa(&upcb->remote_ip), upcb->remote_port);
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            recvQlen = netstat_netconn_recvq(upcb->recv_arg);
            sendQlen = netstat_netconn_sendq(upcb->recv_arg);

            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len - 1), "%-8s%-12d%-12d%-24s%-24s\n",
                      "udp", recvQlen, sendQlen, local_ip_port, remote_ip_port);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }
    }
#endif

#if LWIP_RAW
    if (raw_pcbs != NULL) {
        iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "\n%-8s%-12s%-12s%-20s%-20s%-16s%-16s\n",
          "Type", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "Protocol", "HDRINCL");
        if ((iRet <= 0) || (iRet >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= iRet;
        entry_buf_offset += iRet;

        for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
            (void)memset_s(local_ip_port, sizeof(local_ip_port), 0, sizeof(local_ip_port));
            (void)memset_s(remote_ip_port, sizeof(remote_ip_port), 0, sizeof(remote_ip_port));

            iRet = snprintf_s((char*)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),"%s", ipaddr_ntoa(&rpcb->local_ip));
            if (iRet <= 0 || iRet >= (int)sizeof(local_ip_port)) {
              goto out;
            }

            iRet = snprintf_s((char*)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s", ipaddr_ntoa(&rpcb->remote_ip));
            if (iRet <= 0 || iRet >= (int)sizeof(remote_ip_port)) {
              goto out;
            }

            recvQlen = netstat_netconn_recvq(rpcb->recv_arg);
            sendQlen = netstat_netconn_sendq(rpcb->recv_arg);

    #if PF_PKT_SUPPORT
            proto = rpcb->proto.protocol;
    #else
            proto = rpcb->protocol;
    #endif
            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len - 1), "%-8s%-12d%-12d%-20s%-20s%-16u%-16d\n",
                      "raw", recvQlen, sendQlen, local_ip_port, remote_ip_port, proto, rpcb->hdrincl);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }
    }
#if PF_PKT_SUPPORT
    if (pkt_raw_pcbs != NULL) {
        iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len-1), "\n%-12s%-12s%-12s%-16s%-12s\n",
          "Type", "Recv-Q", "Send-Q", "Protocol", "netif");
        if ((iRet <= 0) || (iRet >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= iRet;
        entry_buf_offset += iRet;

        for (rpcb = pkt_raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {

            recvQlen = netstat_netconn_recvq(rpcb->recv_arg);
            sendQlen = netstat_netconn_sendq(rpcb->recv_arg);

            for (netif = netif_list; netif != NULL; netif = netif->next) {
                if (netif->ifindex == rpcb->netifindex) {
                  iRet = snprintf_s((char*)netif_name, IFNAMSIZ, IFNAMSIZ-1, "%s%d", netif->name, netif->num);
                  if (iRet <= 0 || iRet >= IFNAMSIZ) {
                    goto out;
                  }
                }
            }

            if (netif == NULL) {
                (void)snprintf_s((char*)netif_name, IFNAMSIZ, IFNAMSIZ-1, "%s", "None");
            }

            proto = ntohs(rpcb->proto.eth_proto);

            iRet = snprintf_s((char*)(entry_buf + entry_buf_offset), entry_buf_len, (entry_buf_len - 1), "%-12s%-12d%-12d%-16x%-12s\n",
                      "pkt-raw", recvQlen, sendQlen, proto, netif_name);
            if ((iRet <=0) || (iRet >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= iRet;
            entry_buf_offset += iRet;
        }
    }
#endif
#endif

out:
    ndata->netstat_out_buf_updated_len = entry_buf_offset;
    sys_sem_signal(&ndata->cb_completed);
    return;
}

u32_t osShellNetstat(int argc, char **argv)
{
    struct netstat_data ndata = {0};
    err_t err;

    if (argc > 0)
    {
        PRINTK("\nUsage: netstat\n");
        return LOS_NOK;
    }

    if (0 == tcpip_init_finish)
    {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    ndata.netstat_out_buf = mem_malloc(MAX_NETSTAT_ENTRY);
    if (ndata.netstat_out_buf == NULL) {
        PRINTK("%s: no free mem\n", __FUNCTION__);
        return LOS_NOK;
    }
    ndata.netstat_out_buf_len = MAX_NETSTAT_ENTRY;
    ndata.netstat_out_buf_updated_len = 0;

    if (sys_sem_new(&ndata.cb_completed, 0) != ERR_OK) {
        goto err_hand;
    }

    err = tcpip_callback(netstat_internal, &ndata);
    if (err != ERR_OK) {
        sys_sem_free(&ndata.cb_completed);
        goto err_hand;
    }

    (void)sys_arch_sem_wait(&ndata.cb_completed, 0);
    sys_sem_free(&ndata.cb_completed);
    if ((ndata.netstat_out_buf_updated_len > 0) && (ndata.netstat_out_buf_updated_len < MAX_NETSTAT_ENTRY)) {
        PRINTK("%s\n", ndata.netstat_out_buf);
        mem_free(ndata.netstat_out_buf);
        return LOS_OK;
    }

err_hand:
    mem_free(ndata.netstat_out_buf);
    ndata.netstat_out_buf = NULL;
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(netstat_shellcmd, CMD_TYPE_EX, "netstat",  XARGS, (CMD_CBK_FUNC)osShellNetstat);/*lint !e19*/
#endif /* LOSCFG_SHELL */


#ifdef LWIP_DEBUG_INFO
u32_t netdebug_memp(int argc, char** argv)
{
  int type;
  u32_t ret = LOS_OK;

  if (argc >= 2) {
    if (strcmp("-i", argv[1]) == 0) {
      /* netdebug memp -i */
      if (argc == 2) {
        (void)debug_memp_info();
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-udp", argv[1]) == 0) {
      /* netdebug memp -udp [-v] */
      if (argc == 2) {
        (void)debug_memp_type_info(MEMP_UDP_PCB, 0);
      } else if (argc == 3 && strcmp("-v", argv[2]) == 0) {
        (void)debug_memp_type_info(MEMP_UDP_PCB, 1);
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-tcp", argv[1]) == 0) {
      /* netdebug memp -tcp [-v] */
      if (argc == 2) {
        (void)debug_memp_type_info(MEMP_TCP_PCB, 0);
      } else if (argc == 3 && strcmp("-v", argv[2]) == 0) {
        (void)debug_memp_type_info(MEMP_TCP_PCB, 1);
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-raw", argv[1]) == 0) {
      /* netdebug memp -raw [-v] */
      if (argc == 2) {
        (void)debug_memp_type_info(MEMP_RAW_PCB, 0);
      } else if (argc == 3 && strcmp("-v", argv[2]) == 0) {
        (void)debug_memp_type_info(MEMP_RAW_PCB, 1);
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-conn", argv[1]) == 0) {
      /* netdebug memp -conn [-v] */
      if (argc == 2) {
        (void)debug_memp_type_info(MEMP_NETCONN, 0);
      } else if (argc == 3 && strcmp("-v", argv[2]) == 0) {
        (void)debug_memp_type_info(MEMP_NETCONN, 1);
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-d", argv[1]) == 0) {
      /* netdebug memp -d <type> */
      if (argc == 3) {
        type = atoi(argv[2]);
        if (type >= 0) {
          (void)debug_memp_detail(type);
        } else {
          ret = LOS_NOK;
        }
      } else {
        ret = LOS_NOK;
      }
    }
#if LWIP_DEBUG_TCP_LEAK
    else if (strcmp("-leak", argv[1]) == 0) {
      /* netdebug memp -leak */
      if (argc == 2) {
        (void)debug_memp_leak_info(MEMP_NETCONN);
        (void)debug_memp_leak_info(MEMP_TCP_PCB);
      } else {
        ret = LOS_NOK;
      }
    }
#endif /* LWIP_DEBUG_TCP_LEAK */
  }

  if (ret != LOS_OK) {
    /* Cmd help */
    PRINTK("\nUsage:\n");
    PRINTK("netdebug memp -i\n");
    PRINTK("netdebug memp -d <type>\n");
    PRINTK("netdebug memp -{udp|tcp|raw|conn} [-v]\n");
#if LWIP_DEBUG_TCP_LEAK
    PRINTK("netdebug memp -leak\n");
#endif
  }

  return ret;
}


u32_t netdebug_sock(int argc, char** argv)
{
  int idx;
  u32_t ret = LOS_OK;

  if (argc >= 2) {
    if (strcmp("-i", argv[1]) == 0) {
      /* netdebug sock -i [-v] */
      if (argc == 2) {
        for (idx = 0; idx < LWIP_NUM_SOCKETS; idx++) {
          (void)debug_socket_info(idx, 1, 0, 0);
        }
      } else if (argc == 3 && strcmp("-v", argv[2]) == 0) {
        for (idx = 0; idx < LWIP_NUM_SOCKETS; idx++) {
          (void)debug_socket_info(idx, 1, 0, 1);
        }
      } else {
        ret = LOS_NOK;
      }
    } else if (strcmp("-d", argv[1]) == 0)  {
      /* netdebug sock -d <idx> [-v]  */
      if (argc >= 3) {
        idx = atoi(argv[2]);
        if (argc == 3 && idx >= 0) {
          (void)debug_socket_info(idx, 1, 1, 0);
        } else if (argc == 4 && idx >= 0 && strcmp("-v", argv[3]) == 0) {
          (void)debug_socket_info(idx, 1, 1, 1);
        } else {
          ret = LOS_NOK;
        }
      } else {
        ret = LOS_NOK;
      }
    } else {
      ret = LOS_NOK;
    }
  }

  if (ret != LOS_OK) {
    /* Cmd help */
    PRINTK("\nUsage:\n");
    PRINTK("netdebug sock -i\n");
    PRINTK("netdebug sock -d <idx> [-v]\n");
  }

  return ret;
}


u32_t osShellNetDebug(int argc, char **argv)
{
  PRINTK("\nBootTime %u s\n", sys_now_second());
  if (argc >=1) {
    if (strcmp("memp", argv[0]) == 0) {
      /* netdebug memp {-i | -d <type> | -udp | -tcp | -raw |-conn} */
      return netdebug_memp(argc, argv);
    } else if (strcmp("sock", argv[0]) == 0) {
      /* netdebug sock {-i | -d <idx>} */
      return netdebug_sock(argc, argv);
    }
  }
  /* Cmd help */
  PRINTK("\nUsage:\n");
  PRINTK("netdebug memp -i\n");
  PRINTK("netdebug memp -d <type>\n");
  PRINTK("netdebug memp -{udp|tcp|raw|conn} [-v]\n");
#if LWIP_DEBUG_TCP_LEAK
  PRINTK("netdebug memp -leak\n");
#endif
  PRINTK("netdebug sock -i\n");
  PRINTK("netdebug sock -d <idx> [-v]\n");

  return LOS_NOK;
}
#endif /* LWIP_DEBUG_INFO */

#if defined(LOSCFG_SHELL) && defined(LWIP_DEBUG_INFO)
SHELLCMD_ENTRY(netdebug_shellcmd, CMD_TYPE_EX, "netdebug",  XARGS, (CMD_CBK_FUNC)osShellNetDebug);/*lint !e19*/
#endif /* LOSCFG_SHELL && LWIP_DEBUG_INFO */

/*lint +e732*/

#endif //LWIP_ENABLE_LOS_SHELL_CMD

